home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 41 / Amiga Format CD41 (1999-06)(Future Publishing)(GB)[!][issue 1999-07].iso / -seriously_amiga- / programming / other / flexcat / flexcat.c < prev    next >
C/C++ Source or Header  |  1999-04-19  |  61KB  |  2,690 lines

  1.  
  2. /*****************************************************************
  3. **                                                              **
  4. ** If you use GoldED or any other text editor featuring folding **
  5. ** you may want to set up "///" as fold opening phrase, and     **
  6. ** "//|" as closing one, as this source is using it.            **
  7. **                                                              **
  8. **                                                Marcin        **
  9. **                                                              **
  10. *****************************************************************/
  11.  
  12.  
  13. #define __amigados
  14.  
  15. /// README
  16. /*
  17.  
  18.     FlexCat.c:  The flexible catalog creator
  19.  
  20.     This program is distributed in the hope that it will be useful,
  21.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  22.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  23.  
  24.     Ok, this is nothing special. It grabs a catalog translation and a
  25.     catalog description file and produces catalogs and the source to
  26.     handle them. What is it else than lots of other programs?
  27.  
  28.     The difference is, that YOU determine what source FlexCat produces.
  29.     Another file is scanned by FlexCat to produce code. This file contains
  30.     some c-string like special characters (%v for version for example)
  31.     You can edit this file and modify it as you want. So FlexCat can produce
  32.     C source as well as Assembler, Oberon, Modula 2, E, ...
  33.  
  34. */
  35. //|
  36.  
  37. #define VERSION 2
  38. #define REVISION 2
  39. #define VERS       "FlexCat 2.2"
  40.  
  41. #ifdef _M68060
  42.   #define _CPU "[68060]"
  43. #else
  44.   #ifdef _M68040
  45.     #define _CPU "[68040]"
  46.   #else
  47.     #ifdef _M68030
  48.       #define _CPU "[68030]"
  49.     #else
  50.       #ifdef _M68020
  51.         #define _CPU "[68020]"
  52.       #else
  53.         #ifdef _M68010
  54.           #define _CPU "[68010]"
  55.         #else
  56.           #define _CPU "[680x0]"
  57.         #endif
  58.       #endif
  59.     #endif
  60.   #endif
  61. #endif
  62.  
  63. #define VSTRING  VERS " " _CPU " " __AMIGADATE__
  64. #define VERSTAG  "$VER: " VSTRING
  65.  
  66.  
  67. /// Includes and defines
  68.  
  69. #include <stdlib.h>
  70. #include <stdio.h>
  71. #include <string.h>
  72. #include <ctype.h>
  73. #include <time.h>
  74. #include <dos.h>
  75. #include "FlexCat_cat.h"
  76.  
  77. #if ((defined(_DCC) && defined(AMIGA))       ||     \
  78.      (defined(__SASC) && defined(_AMIGA)))      &&  \
  79.     !defined(__amigados)
  80. #define __amigados
  81. #endif
  82.  
  83. #if defined(__amigados)
  84. #include <exec/types.h>
  85. #if defined(_DCC) || defined(__SASC) || defined(__GNUC__)
  86. #include <proto/exec.h>
  87. #include <proto/dos.h>
  88. #include <proto/intuition.h>
  89. #include <proto/utility.h>
  90. #else
  91. #include <clib/exec_protos.h>
  92. #include <clib/dos_protos.h>
  93. #include <clib/utility_protos.h>
  94. #endif
  95.  
  96. #ifdef tolower
  97. #undef tolower
  98. #endif
  99. #define tolower         ToLower
  100. #define stricmp(s,t)    Stricmp((STRPTR) (s), (STRPTR) (t))
  101. #define strnicmp(s,t,l) Strnicmp((STRPTR) (s), (STRPTR) (t), l)
  102.  
  103. #endif
  104.  
  105.  
  106. #ifndef FALSE
  107. #define FALSE 0
  108. #endif
  109. #ifndef TRUE
  110. #define TRUE (!FALSE)
  111. #endif
  112.  
  113.  
  114. #define MAXPATHLEN 512
  115. #define FLEXCAT_SDDIR "FLEXCAT_SDDIR"
  116. #if defined(__amigados)
  117. #define DEFAULT_FLEXCAT_SDDIR "PROGDIR:lib"
  118. #else
  119. #define DEFAULT_FLEXCAT_SDDIR "lib"
  120. #endif
  121.  
  122. #if defined(__amigados)
  123. #define MAX_PREFS_LEN 512
  124. #define FLEXCAT_PREFS "flexcat.prefs"
  125. char    prefs_sddir[MAXPATHLEN] = "\0";
  126. #endif
  127.  
  128.  
  129. //|
  130. /// Structs
  131.  
  132. enum StringTypes {
  133.     TYPE_C,         /*  Produce C strings                   */
  134.     TYPE_ASSEMBLER, /*  Produce Assembler strings           */
  135.     TYPE_OBERON,    /*  Produce Oberon strings              */
  136.     TYPE_E,         /*  Produce E strings. (Oops, thought   */
  137.                     /*  it allows only 32 bit integers? ;-) */
  138.     TYPE_NONE       /*  Simple strings                      */
  139. };
  140.  
  141.  
  142. enum OutputModes {
  143.     OutputMode_None,    /*  Nothing written yet                 */
  144.     OutputMode_Bin,     /*  Last character written was binary   */
  145.     OutputMode_Ascii    /*  Last character written was Ascii    */
  146. };
  147.  
  148. struct CatString
  149. { struct CatString *Next;
  150.   char *CD_Str;
  151.   char *CT_Str;
  152.   char *ID_Str;
  153.   int MinLen, MaxLen, ID, Nr;
  154.   int NotInCT;          /* If string is not present we write NEW    */
  155.                         /* while updating CT file, for easier work. */
  156.  
  157. };
  158.  
  159. struct CDLine
  160. { struct CDLine *Next;
  161.   char *Line;
  162. };
  163.  
  164. struct CatalogChunk
  165. { struct CatalogChunk *Next;
  166.   ULONG ID;
  167.   char *ChunkStr;
  168. };
  169.  
  170. struct CatString *FirstCatString = NULL;  /*  First catalog string            */
  171. struct CDLine *FirstCDLine = NULL;        /*  First catalog description line  */
  172. struct CatalogChunk *FirstChunk = NULL;   /*  List of catalog chunks          */
  173.  
  174. char *BaseName   = "";              /*  Basename of catalog description */
  175. char *Language   = "english";       /*  Language of catalog description */
  176. int  CatVersion  = 0;               /*  Version of catalog to be opened */
  177. int  LengthBytes = 0;               /*  Number of bytes to preceed a    */
  178.                                     /*  created string and containing   */
  179.                                     /*  its length.                     */
  180. char *CatLanguage      = NULL;      /*  Language of catalog translation */
  181. char *CatVersionString = NULL;      /*  version string of catalog       */
  182.                                     /*  translation (## version)        */
  183. char *CatRcsId = NULL;              /*  rcs ID of catalog translation   */
  184.                                     /*  (## rcsid)                      */
  185. char *CatName = NULL;               /*  name of catalog translation     */
  186. int  CodeSet = 0;                   /*  Codeset of catalog translation  */
  187. int  NumStrings = 0;                /*  Number of catalog strings       */
  188. int  LongStrings = TRUE;            /*  Generate long or short strings  */
  189.  
  190. char *ScanFile;                     /*  File currently scanned          */
  191. int  ScanLine;                      /*  Line currently scanned          */
  192.  
  193. int  GlobalReturnCode = 0;          /*  Will be 5, if warnings appear    */
  194. int  WarnCTGaps = FALSE;            /*  Warn missing symbols in CT       */
  195.                                     /*  file.                            */
  196. int  NoOptim = FALSE;               /*  Put string into catalog even     */
  197.                                     /*  if translation is equal to       */
  198.                                     /*  description.                     */
  199. int  Fill    = FALSE;               /*  It translation of given string   */
  200.                                     /*  is missing or it's empty, write  */
  201.                                     /*  string descriptor from #?.cd     */
  202.                                     /*  file instead.                    */
  203. int  DoExpunge = FALSE;             /*  If TRUE FlexCat will do AVAIL    */
  204.                                     /*  FLUSH alike after catalog save   */
  205. int  NoBeep = FALSE;                /*  if TRUE, FlexCat won't call      */
  206.                                     /*  DisplayBeep() any longer         */
  207. int  Quiet   = FALSE;               /*  Forces FlexCat to shut up        */
  208.  
  209. int  NumberOfWarnings = 0;          /* We count warnings to be smart     */
  210.                                     /* and not to do Beep bombing, but   */
  211.                                     /* call DisplayBeep() only once      */
  212. int  CT_Scanned = FALSE;            /* If TRUE, and we are going to      */
  213.                                     /* write new #?.ct file, then user   */
  214.                                     /* surely updates own #?.ct file     */
  215.                                     /* so we should write ***NEW***      */
  216.                                     /* whenever necessary.               */
  217. int  LANGToLower = TRUE;            /* Shall we do ToLower() on lang's   */
  218.                                     /* name? Some #?.language seems to   */
  219.                                     /* be broken, so we allow workaround */
  220. int  NoBufferedIO = FALSE;          /* Shall we do buffered IO           */
  221. int  buffer_size = 2048;            /* Size of the IO buffer             */
  222. int  Modified = FALSE;              /* Shall we write the catalog ONLY   */
  223.                                     /* if #?.catalog is younger than     */
  224.                                     /* #?.c(d|t) files?                  */
  225.  
  226. #define MAX_NEW_STR_LEN 25
  227. char Msg_New[MAX_NEW_STR_LEN]    = "***NEW***";
  228.                                     /*  new strings in updated #?.ct    */
  229.  
  230. int  CopyNEWs = FALSE;
  231. char Old_Msg_New[MAX_NEW_STR_LEN] = "; ***NEW***";
  232.  
  233.                                     /*  old newstring (above) used in old   */
  234.                                     /* CT file. Now we look if it's present */
  235.                                     /* and copy it into new CT if user does */
  236.                                     /* upgrade (flexcat CD CT newctfile CT  */
  237.  
  238. char VersTag[] = VERSTAG;
  239. char VString[] = VSTRING " by Jochen Wiedmann and Marcin Orlowski";
  240. char EString[] = "E-mail: carlos@amiga.com.pl  WWW: http://amiga.com.pl/flexcat/";
  241. //|
  242.  
  243. /// FUNC: ReadPrefs
  244. #if defined(__amigados)
  245.  
  246. char ReadPrefs(void)
  247. {
  248. enum{ SDDIR,
  249.       MSG_NEW,
  250.       WARNCTGAPS,
  251.       NOOPTIM,
  252.       FILL,
  253.       FLUSH,
  254.       NOBEEP,
  255.       QUIET,
  256.       NOLANGTOLOWER,
  257.       NOBUFFEREDIO,
  258.       MODIFIED,
  259.       COPYMSGNEW,
  260.       OLDMSGNEW,
  261.  
  262.       ARGS_COUNT
  263.     };
  264.  
  265. char   template[] = "SDDIR/K,MSG_NEW/K,WARNCTGAPS/S,NOOPTIM/S,FILL/S,FLUSH/S,NOBEEP/S,QUIET/S,NOLANGTOLOWER/S,NOBUFFEREDIO/S,MODIFIED/S,COPYMSGNEW/S,OLDMSGNEW/K";
  266. LONG   Results[ARGS_COUNT] = {0};
  267. char   result = FALSE;
  268. char   *prefs;
  269. struct RDArgs *rda;
  270. struct RDArgs *rdargs;
  271.  
  272.   if(prefs = getenv(FLEXCAT_PREFS))
  273.     {
  274.     prefs = realloc(prefs, strlen(prefs)+1);
  275.     strcat(prefs, "\n");
  276.  
  277.     if(rda = AllocDosObject(DOS_RDARGS, TAG_DONE))
  278.        {
  279.        rda->RDA_Source.CS_Buffer = prefs;
  280.        rda->RDA_Source.CS_Length = strlen(prefs);
  281.        rda->RDA_Source.CS_CurChr = 0;
  282.        rda->RDA_Flags |= RDAF_NOPROMPT;
  283.  
  284.        if(rdargs = ReadArgs(template, Results, rda))
  285.          {
  286.          if(Results[SDDIR])
  287.            strncpy(prefs_sddir, (char *)Results[SDDIR], MAXPATHLEN);
  288.  
  289.          if(Results[MSG_NEW])
  290.            strncpy(Msg_New, (char *)Results[MSG_NEW], MAX_NEW_STR_LEN);
  291.  
  292.          WarnCTGaps   = Results[WARNCTGAPS];
  293.          NoOptim      = Results[NOOPTIM];
  294.          Fill         = Results[FILL];
  295.          DoExpunge    = Results[FLUSH];
  296.          NoBeep       = Results[NOBEEP];
  297.          Quiet        = Results[QUIET];
  298.          LANGToLower  = Results[NOLANGTOLOWER];
  299.          Modified     = Results[MODIFIED];
  300.          NoBufferedIO = Results[NOBUFFEREDIO];
  301.          CopyNEWs     = Results[COPYMSGNEW];
  302.          if(Results[OLDMSGNEW])
  303.            sprintf(Old_Msg_New, "; %s", (char *)Results[OLDMSGNEW]);
  304.  
  305.          FreeArgs(rdargs);
  306.  
  307.          result = TRUE;
  308.          }
  309.        else
  310.          {
  311.          fputs((char *)msgPrefsError, stderr);
  312.          fputs((char *)template, stderr);
  313.          fputs((char *)"\n", stderr);
  314.          DisplayBeep(NULL);
  315.          }
  316.  
  317.        FreeDosObject(DOS_RDARGS, rda);
  318.        }
  319.      else
  320.        {
  321.        fputs("Error processing prefs.\nCan't AllocDosObject()\n", stderr);
  322.        }
  323.  
  324.     free(prefs);
  325.     }
  326.  
  327.   return(result);
  328. }
  329.  
  330. #endif
  331. //|
  332.  
  333. /// FUNC: MyExit
  334. void MyExit (int Code)
  335. {
  336.  
  337. #if defined(__amigados)
  338.  
  339.   if(((NumberOfWarnings > 0) ||(Code !=0)) && (!NoBeep))
  340.      DisplayBeep(NULL);
  341.  
  342. #endif
  343.  
  344.     exit(Code);
  345. }
  346. //|
  347.  
  348. /// FUNC: ShowError
  349.  
  350. /*
  351.     This shows an error message and terminates
  352. */
  353. struct RDArgs *Args;
  354. void ShowError(const UBYTE (*msg), ...)
  355.  
  356. { char **ptr = (char **) &msg;
  357.  
  358. //  if(!Quiet)
  359.     {
  360.     fprintf(stderr, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4]);
  361.     putc('\n', stderr);
  362.     }
  363.  
  364. #if defined(__amigados)
  365.   NumberOfWarnings++;
  366. #endif
  367.  
  368.   MyExit(10);
  369. }
  370. //|
  371. /// FUNC: MemError
  372.  
  373. /*
  374.     This shows the message: Memory error.
  375. */
  376. void MemError(void)
  377.  
  378. {
  379.   ShowError(msgMemoryError, NULL);
  380. }
  381. //|
  382. /// FUNC: ShowWarn
  383.  
  384. /*
  385.     This shows a warning
  386. */
  387. void ShowWarn(const UBYTE (*msg), ...)
  388.  
  389. { char **ptr = (char **) &msg;
  390.  
  391.   if(!Quiet)
  392.     {
  393.     fprintf(stderr, (char *) msgWarning, ScanFile, ScanLine);
  394.     fprintf(stderr, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4]);
  395.     putc('\n', stderr);
  396.     }
  397.  
  398.   NumberOfWarnings++;
  399.   GlobalReturnCode = 5;
  400. }
  401. //|
  402. /// FUNC: AllocString
  403.  
  404. /*
  405.     This allocates a string
  406. */
  407. char *AllocString(const char *str)
  408.  
  409. { char *ptr;
  410.  
  411.   if (!(ptr = malloc(strlen(str)+1)))
  412.   { MemError();
  413.   }
  414.   strcpy(ptr, str);
  415.   return(ptr);
  416. }
  417. //|
  418. /// FUNC: Add catalog chunk
  419.  
  420. /*
  421.     This adds a new catalog chunk to the list of catalog
  422.     chunks.
  423. */
  424. char *AddCatalogChunk(char *ID, const char *string)
  425. {
  426.   struct CatalogChunk *cc, **ccptr;
  427.  
  428.   if (!(cc = malloc(sizeof(*cc))))
  429.   { MemError();
  430.   }
  431.   cc->Next = NULL;
  432.   cc->ID = *((ULONG *) ID);
  433.   cc->ChunkStr = AllocString(string);
  434.  
  435.   /*
  436.       Put the new chunk to the end of the chunk list.
  437.   */
  438.   for (ccptr = &FirstChunk;  *ccptr != NULL;  ccptr = &(*ccptr)->Next)
  439.   {
  440.   }
  441.   *ccptr = cc;
  442.   return(cc->ChunkStr);
  443. }
  444. //|
  445. /// FUNC: gethex
  446. /*
  447.     This translates a hex character.
  448. */
  449. int gethex(int c)
  450. {
  451.   if (c >= '0'  &&  c <= '9')
  452.   { return(c - '0');
  453.   }
  454.   else if (c >= 'a'  &&  c <= 'f')
  455.   { return(c - 'a' + 10);
  456.   }
  457.   else if (c >= 'A'  &&  c <= 'F')
  458.   { return(c - 'A' + 10);
  459.   }
  460.   ShowWarn(msgExpectedHex);
  461.   return(0);
  462. }
  463. //|
  464. /// FUNC: getoctal
  465.  
  466. /*
  467.     This translates an octal digit.
  468. */
  469. int getoctal(int c)
  470. {
  471.  
  472.   if (c >= '0'  &&  c <= '7')
  473.     {
  474.     return(c - '0');
  475.     }
  476.  
  477.   ShowWarn(msgExpectedOctal);
  478.   return(0);
  479.  
  480. }
  481. //|
  482. /// FUNC: ReadLine
  483.  
  484. /*
  485.     Reading a line is somewhat complicated in order to allow lines of any
  486.     length.
  487.  
  488.     Inputs: fp           - the file, where the input comes from
  489.             AllowComment - TRUE, if a leading semicolon should force to
  490.                            interpret the line as a comment line
  491. */
  492. #define BUFSIZE 4096
  493. char *ReadLine(FILE *fp, int AllowComment)
  494. {
  495.  
  496.   char *OldLine, *NewLine = NULL;
  497.   int c = '\0';
  498.   int Len = 0, LineLen = 0;
  499.   int FirstChar = TRUE;
  500.   int BackslashSeen   = FALSE;
  501.   int BackslashSeenOn = 0;     /* position the last backslash was seen on */
  502.   int CommentLine = FALSE;     /* if TRUE we should ignore normally treat trailing \'s */
  503.  
  504.   while(c != EOF)
  505.     {
  506.     if(Len+10 > LineLen)
  507.       {
  508.       OldLine = NewLine;
  509.       if(!(NewLine = malloc(LineLen+BUFSIZE)))
  510.         MemError();
  511.  
  512.       strncpy(NewLine, OldLine, LineLen);
  513.       if(OldLine)
  514.         free(OldLine);
  515.  
  516.       LineLen += BUFSIZE;
  517.       }
  518.  
  519.     c = getc(fp);
  520.  
  521.     if(FirstChar)
  522.       {
  523.       if(c == EOF)
  524.         {
  525.         free(NewLine);
  526.         return(NULL);
  527.         }
  528.  
  529.       if(c == ';')
  530.         {
  531.         CommentLine = TRUE;
  532.         }
  533.  
  534.       FirstChar = FALSE;
  535.       }
  536.  
  537.     switch(c)
  538.       {
  539.       case '\r':
  540.         break;
  541.  
  542.       case '\n':
  543.         ++ScanLine;
  544.         if(BackslashSeen)
  545.           {
  546.           NewLine[Len++] = c;
  547.           BackslashSeen = FALSE;
  548.           break;
  549.           }
  550.         c = EOF;
  551.  
  552.       case EOF:
  553.         break;
  554.  
  555.                                  /*  Let's check for trailing \\ */
  556.       case '\\':
  557.         {
  558.         if(!CommentLine)
  559.           {
  560.           if(BackslashSeen)
  561.             {
  562.             if(BackslashSeenOn == (Len-1))
  563.               {
  564.               BackslashSeen = FALSE;
  565.               NewLine[Len++] = c;
  566.               break;
  567.               }
  568.             }
  569.  
  570.           BackslashSeen = TRUE;
  571.           BackslashSeenOn = Len;
  572.           }
  573.  
  574.         NewLine[Len++] = c;
  575.         break;
  576.         }
  577.  
  578.  
  579.       default:
  580.         BackslashSeen = FALSE;
  581.         NewLine[Len++] = c;
  582.       }
  583.     }
  584.  
  585.   NewLine[Len] = '\0';
  586.  
  587.   return(NewLine);
  588.  
  589. }
  590. //|
  591. /// FUNC: OverSpace
  592.  
  593. /*
  594.     This removes trailing blanks.
  595. */
  596. void OverSpace(char **strptr)
  597.  
  598. { int c;
  599.  
  600.   while ((c = **strptr) == ' '  ||  c == '\t')
  601.   { (*strptr)++;
  602.   }
  603. }
  604. //|
  605.  
  606. /// FUNC: Expunge
  607.  
  608. void Expunge(void)
  609. {
  610. #if defined(__amigados)
  611.  
  612.  
  613.   if(DoExpunge)
  614.     {
  615. #ifdef __EXPUNGE_ALL__
  616.     APTR Memory;
  617.  
  618.     if(Memory = AllocMem(-1, NULL))
  619.        FreeMem(Memory, -1);                // just in case ;-)
  620. #else
  621.  
  622. #pragma libcall LocaleBase localeExpunge 12 00
  623. VOID localeExpunge(VOID);
  624.  
  625.     struct Library    *LocaleBase;
  626.  
  627.     if(LocaleBase = OpenLibrary("locale.library", 0))
  628.        {
  629.        localeExpunge();
  630.        CloseLibrary(LocaleBase);
  631.        }
  632.  
  633. #endif
  634.     }
  635. #endif
  636.  
  637. }
  638.  
  639. //|
  640.  
  641. /// FUNC: ReadChar
  642.  
  643. /*
  644.     ReadChar scans an input line translating the backslash characters.
  645.  
  646.     Inputs: strptr  - a pointer to a stringpointer; the latter points to the
  647.                       next character to be read and points behind the read
  648.                       bytes after executing ReadChar
  649.             dest    - a pointer to a buffer, where the read bytes should be
  650.                       stored
  651.  
  652.     Result: number of bytes that are written to dest (between 0 and 2)
  653. */
  654. int ReadChar(char **strptr, char *dest)
  655. {
  656.   char c;
  657.   int i;
  658.  
  659.   switch(c = *((*strptr)++))
  660.     {
  661.     case '\\':
  662.  
  663.       switch(c = tolower((int) *((*strptr)++)))
  664.         {
  665.         case '\n':
  666.           return(0);
  667.         case 'b':
  668.           *dest = '\b';
  669.           break;
  670.         case 'c':
  671.           *dest = '\233';
  672.           break;
  673.         case 'e':
  674.           *dest = '\033';
  675.           break;
  676.         case 'f':
  677.           *dest = '\f';
  678.           break;
  679.         case 'g':
  680.           *dest = '\007';
  681.           break;
  682.         case 'n':
  683.           *dest = '\n';
  684.           break;
  685.         case 'r':
  686.           *dest = '\r';
  687.           break;
  688.         case 't':
  689.           *dest = '\t';
  690.           break;
  691.         case 'v':
  692.           *dest = '\013';
  693.           break;
  694.         case 'x':
  695.           *dest = gethex((int) **strptr);
  696.           (*strptr)++;
  697.           if (((c = **strptr) >= '0'  &&  c <= '9')  ||
  698.               (c >= 'a'  &&  c <= 'f')  ||  (c >= 'A'  &&  c <= 'F'))
  699.           { *dest = (*dest << 4) + gethex((int) c);
  700.             (*strptr)++;
  701.           }
  702.           break;
  703.         case '0':
  704.         case '1':
  705.         case '2':
  706.         case '3':
  707.         case '4':
  708.         case '5':
  709.         case '6':
  710.         case '7':
  711.  
  712.           *dest = getoctal((int)c);
  713.  
  714.           for(i = 0;  i < 2;  i++)
  715.             {
  716.             if((c = **strptr) >= '0'  &&  c <= '7')
  717.               {
  718.               *dest = (*dest << 3) + getoctal((int) c);
  719.               (*strptr)++;
  720.               }
  721.             }
  722.           break;
  723.         case ')':
  724.         case '\\':
  725.           *(dest++) = '\\';
  726.           *dest = c;
  727.           return(2);
  728.         default:
  729.           *dest = c;
  730.       }
  731.       break;
  732.  
  733.     default:
  734.       *dest = c;
  735.   }
  736.   return(1);
  737. }
  738. //|
  739. /// FUNC: ScanCDFile
  740.  
  741. /*
  742.     This scans the catalog description file.
  743.  
  744.     Inputs: cdfile  - name of the catalog description file
  745.  
  746.     Result: TRUE, if successful, FALSE otherwise
  747. */
  748. int ScanCDFile(char *cdfile)
  749. {
  750.   FILE *fp;
  751.   struct CDLine *cdline, **cdptr = &FirstCDLine;
  752.   struct CatString *cs, **csptr = &FirstCatString;
  753.   char *line, *newline;
  754.   char *ptr;
  755.   int NextID = 0, len;
  756.   int Result = TRUE;
  757.  
  758.   ScanFile = cdfile;
  759.   ScanLine = 0;
  760.  
  761.   if(!(fp = fopen(cdfile, "r")))
  762.     {
  763.     ShowError(msgNoCatalogDescription, cdfile);
  764.     }
  765.  
  766.   if(!NoBufferedIO)
  767.     setvbuf(fp, NULL, _IOFBF, buffer_size);
  768.  
  769.   /*
  770.       Get the basename
  771.   */
  772.   if ((ptr = strchr(cdfile, ':')))
  773.   { cdfile = ptr+1;
  774.   }
  775.   if ((ptr = strrchr(cdfile, '/')))
  776.   { cdfile = ptr+1;
  777.   }
  778.   if ((ptr = strrchr(cdfile, '.')))
  779.   { len = ptr-cdfile;
  780.   }
  781.   else
  782.   { len = strlen(cdfile);
  783.   }
  784.   if (!(BaseName = malloc(len+1)))
  785.   { MemError();
  786.   }
  787.   strncpy(BaseName, cdfile, len);
  788.   BaseName[len] = '\0';
  789.  
  790.   while(!feof(fp)  &&  (line = newline = ReadLine(fp, TRUE)))
  791.   {
  792.     if(!(cdline = malloc(sizeof(*cdline))))
  793.       {
  794.       MemError();
  795.       }
  796.  
  797.     *cdptr = cdline;
  798.     cdptr = &cdline->Next;
  799.     cdline->Next = NULL;
  800.     cdline->Line = line = AllocString(newline);
  801.     free(newline);
  802.  
  803.     if (*line == ';')
  804.       {
  805.       continue;
  806.       }
  807.  
  808.     if(*line == '#')
  809.       {
  810.       int CheckExtra = TRUE;
  811.  
  812.       if (strnicmp(line+1, "language", 8) == 0)
  813.         {
  814.         char *ptr;
  815.  
  816.         line += 9;
  817.         OverSpace(&line);
  818.         Language = AllocString(line);
  819.  
  820.         if(LANGToLower)
  821.            {
  822.            for (ptr = Language;  *ptr;  ptr++)
  823.              {
  824.              *ptr = tolower((int) *ptr);
  825.              }
  826.            CheckExtra = FALSE;
  827.            }
  828.  
  829.         }
  830.       else
  831.         if(strnicmp(line+1, "version", 7) == 0)
  832.           {
  833.           CatVersion = strtol(line+8, &line, 0);
  834.           }
  835.         else
  836.           {
  837.           if(strnicmp(line+1, "basename", 8) == 0)
  838.            {
  839.            line += 9;
  840.            OverSpace(&line);
  841.            free(BaseName);
  842.            BaseName = AllocString(line);
  843.            CheckExtra = FALSE;
  844.            }
  845.           else
  846.            {
  847.            ShowWarn(msgUnknownCDCommand);
  848.            Result = FALSE;
  849.            CheckExtra = FALSE;
  850.            }
  851.          }
  852.  
  853.       if(CheckExtra)
  854.         {
  855.         OverSpace(&line);
  856.           if(*line)
  857.             {
  858.             ShowWarn(msgExtraCharacters);
  859.             Result = FALSE;
  860.             }
  861.         }
  862.       }
  863.     else
  864.       {
  865.       char *idstr;
  866.  
  867.       if(*line == ' '  ||  *line == '\t')
  868.         {
  869.         ShowWarn(msgUnexpectedBlanks);
  870.         Result = FALSE;
  871.         OverSpace(&line);
  872.         }
  873.  
  874.       idstr = line;
  875.       while ((*line >= 'a'  &&  *line <= 'z')  ||
  876.              (*line >= 'A'  &&  *line <= 'Z')  ||
  877.              (*line >= '0'  &&  *line <= '9')  ||
  878.              *line == '_')
  879.         {
  880.         ++line;
  881.         }
  882.  
  883.       if(idstr == line)
  884.         {
  885.         ShowWarn(msgNoIdentifier);
  886.         Result = FALSE;
  887.         }
  888.       else
  889.         {
  890.         int found;
  891.  
  892.         if(!(cs = malloc(sizeof(*cs))))
  893.           {
  894.           MemError();
  895.           }
  896.  
  897.         do
  898.           {
  899.           struct CatString *scs;
  900.  
  901.           found = TRUE;
  902.           for(scs = FirstCatString;  scs != NULL;  scs = scs->Next)
  903.             {
  904.             if(scs->ID == NextID)
  905.               {
  906.               found = FALSE;
  907.               ++NextID;
  908.               break;
  909.               }
  910.             }
  911.           }
  912.         while(!found);
  913.  
  914.         cs->Next = NULL;
  915.         cs->ID = NextID;
  916.         cs->MinLen = 0;
  917.         cs->MaxLen = -1;
  918.         cs->CD_Str = "";
  919.         cs->CT_Str = NULL;
  920.         cs->NotInCT= TRUE;
  921.  
  922.         if(!(cs->ID_Str = malloc((line-idstr)+1)))
  923.           {
  924.           MemError();
  925.           }
  926.         strncpy(cs->ID_Str, idstr, line-idstr);
  927.         cs->ID_Str[line-idstr] = '\0';
  928.  
  929.         OverSpace(&line);
  930.  
  931.         if(*line != '(')
  932.           {
  933.           ShowWarn(msgNoLeadingBracket);
  934.           Result = FALSE;
  935.           }
  936.         else
  937.           {
  938.           char *oldstr;
  939.           struct CatString *scs;
  940.           char bytes[10];
  941.           int bytesread, reallen;
  942.  
  943.           ++line;
  944.           OverSpace(&line);
  945.           if(*line != '/')
  946.             {
  947.             if(*line == '+')
  948.               {
  949.               NextID = cs->ID = NextID + strtol(line, &line, 0);
  950.               }
  951.             else
  952.               {
  953.               cs->ID = NextID = strtol(line, &line, 0);
  954.               }
  955.  
  956.             OverSpace(&line);
  957.             }
  958.  
  959.           for(scs = FirstCatString;  scs != NULL;  scs = scs->Next)
  960.           { if (scs->ID == cs->ID)
  961.             { ShowWarn(msgDoubleID);
  962.               Result = FALSE;
  963.             }
  964.             if (strcmp(cs->ID_Str, scs->ID_Str)  ==  0)
  965.             { ShowWarn(msgDoubleIdentifier);
  966.               Result = FALSE;
  967.             }
  968.           }
  969.  
  970.           if (*line != '/')
  971.           { ShowWarn(msgNoMinLen);
  972.             Result = FALSE;
  973.           }
  974.           else
  975.           { ++line;
  976.             OverSpace(&line);
  977.             if (*line != '/')
  978.             { cs->MinLen = strtol(line, &line, 0);
  979.               OverSpace(&line);
  980.             }
  981.             if (*line != '/')
  982.             { ShowWarn(msgNoMaxLen);
  983.               Result = FALSE;
  984.             }
  985.             else
  986.             { ++line;
  987.               OverSpace(&line);
  988.               if (*line != ')')
  989.               { cs->MaxLen = strtol(line, &line, 0);
  990.                 OverSpace(&line);
  991.               }
  992.               if (*line != ')')
  993.               { ShowWarn(msgNoTrailingBracket);
  994.                 Result = FALSE;
  995.               }
  996.               else
  997.               { ++line;
  998.                 OverSpace(&line);
  999.                 if (*line)
  1000.                 { ShowWarn(msgExtraCharacters);
  1001.                 }
  1002.               }
  1003.             }
  1004.           }
  1005.         if (!(newline = ReadLine(fp, FALSE)))
  1006.         { ShowWarn(msgNoString);
  1007.           Result = FALSE;
  1008.           cs->CD_Str = "";
  1009.         }
  1010.         else
  1011.         { cs->CD_Str = AllocString(newline);
  1012.           free(newline);
  1013.         }
  1014.  
  1015.         /*
  1016.             Get stringlen
  1017.         */
  1018.         oldstr = cs->CD_Str;
  1019.         reallen = 0;
  1020.         while (*oldstr)
  1021.         { bytesread = ReadChar(&oldstr, bytes);
  1022.           if (bytesread == 2)
  1023.           { bytesread--;
  1024.           }
  1025.           reallen += bytesread;
  1026.         }
  1027.  
  1028.         if (cs->MinLen > 0  &&  reallen < cs->MinLen)
  1029.         { ShowWarn(msgShortString);
  1030.         }
  1031.         if (cs->MaxLen > 0  &&  reallen > cs->MaxLen)
  1032.         { ShowWarn(msgLongString);
  1033.         }
  1034.  
  1035.         cs->Nr = NumStrings;
  1036.  
  1037.         *csptr = cs;
  1038.         csptr = &cs->Next;
  1039.         ++NumStrings;
  1040.         }
  1041.       }
  1042.     }
  1043.   }
  1044.   fclose(fp);
  1045.   return(Result);
  1046. }
  1047. //|
  1048. /// FUNC: ScanCTFile
  1049.  
  1050. /*
  1051.     This scans a catalog translation file.
  1052.  
  1053.     Inputs: ctfile      - name of the translation file to scan.
  1054.  
  1055.     Result: TRUE, if successful, FALSE otherwise.
  1056. */
  1057. int ScanCTFile(char *ctfile)
  1058. {
  1059.   FILE *fp;
  1060.   char *newline, *line, *idstr, *newidstr, *newstr;
  1061.   struct CatString *cs=NULL;
  1062.   int Result = TRUE;
  1063.  
  1064.   ScanFile = ctfile;
  1065.   ScanLine = 0;
  1066.  
  1067.   if (!(fp = fopen(ctfile, "r")))
  1068.     {
  1069.     ShowError(msgNoCatalogTranslation, ctfile);
  1070.     }
  1071.  
  1072.   if(!NoBufferedIO)
  1073.     setvbuf(fp, NULL, _IOFBF, buffer_size);
  1074.  
  1075.  
  1076.   while (!feof(fp)  &&  (line = newline = ReadLine(fp, TRUE)))
  1077.     {
  1078.     switch(*line)
  1079.       {
  1080.       case ';':
  1081.         if( CopyNEWs == TRUE )
  1082.            {
  1083.            if(strnicmp( line, Old_Msg_New, strlen(Old_Msg_New) ) == 0)
  1084.              {
  1085.              cs->NotInCT = TRUE;
  1086.              }
  1087.            }
  1088.       break;
  1089.  
  1090.       case '#':
  1091. ///       looking for command;
  1092.         if(*(++line) != '#')
  1093.           {
  1094.           ShowWarn(msgNoCTCommand);
  1095.           }
  1096.         ++line;
  1097.         OverSpace(&line);
  1098.         if (strnicmp(line, "version", 7) == 0)
  1099.         { if (CatVersionString || CatRcsId || CatName)
  1100.           { ShowWarn(msgDoubleCTVersion);
  1101.           }
  1102.           line += 7;
  1103.           OverSpace(&line);
  1104.           CatVersionString = AllocString(line);
  1105.         }
  1106.         else if (strnicmp(line, "codeset", 7) == 0)
  1107.         { line += 7;
  1108.           CodeSet = strtol(line, &line, 0);
  1109.           OverSpace(&line);
  1110.           if (*line)
  1111.           { ShowWarn(msgExtraCharacters);
  1112.           }
  1113.         }
  1114.         else if (strnicmp(line, "language", 8) == 0)
  1115.         { char *ptr;
  1116.  
  1117.           if (CatLanguage)
  1118.           { ShowWarn(msgDoubleCTLanguage);
  1119.           }
  1120.           line += 8;
  1121.           OverSpace(&line);
  1122.           CatLanguage = AddCatalogChunk("LANG", line);
  1123.  
  1124.           if(LANGToLower)
  1125.             for (ptr = CatLanguage;  *ptr;  ptr++)
  1126.               *ptr = tolower((int) *ptr);
  1127.         }
  1128.         else if (strnicmp(line, "chunk", 5) == 0)
  1129.         { char *ID;
  1130.  
  1131.           line += 5;
  1132.           OverSpace(&line);
  1133.           ID = line;
  1134.           line += sizeof(ULONG);
  1135.           OverSpace(&line);
  1136.  
  1137.           AddCatalogChunk(ID, AllocString(line));
  1138.         }
  1139.         else if (strnicmp(line, "rcsid", 5) == 0)
  1140.         { if (CatVersionString || CatRcsId)
  1141.           { ShowWarn(msgDoubleCTVersion);
  1142.           }
  1143.           line += 5;
  1144.           OverSpace(&line);
  1145.           CatRcsId = AllocString(line);
  1146.         }
  1147.         else if (strnicmp(line, "name", 5) == 0)
  1148.         { if (CatVersionString || CatName)
  1149.           { ShowWarn(msgDoubleCTVersion);
  1150.           }
  1151.           line += 4;
  1152.           OverSpace(&line);
  1153.           CatName = AllocString(line);
  1154.         }
  1155.         else if (strnicmp(line+1, "lengthbytes", 11) == 0)
  1156.         { line += 12;
  1157.           if ((LengthBytes = strtol(line, &line, 0))
  1158.                            > sizeof(long))
  1159.           { ShowWarn(msgNoLengthBytes, sizeof(long));
  1160.             LengthBytes = sizeof(long);
  1161.           }
  1162.         }
  1163.         else
  1164.         {
  1165.         ShowWarn(msgUnknownCTCommand);
  1166.         }
  1167. //|
  1168.         break;
  1169.  
  1170.       default:
  1171.         if(*line == ' '  ||  *line == '\t')
  1172.           {
  1173.           ShowWarn( msgUnexpectedBlanks );
  1174.           OverSpace( &line );
  1175.           }
  1176.         idstr = line;
  1177.  
  1178.         while ((*line >= 'a'  &&  *line <= 'z')  ||
  1179.                (*line >= 'A'  &&  *line <= 'Z')  ||
  1180.                (*line >= '0'  &&  *line <= '9')  ||
  1181.                *line == '_')
  1182.         { ++line;
  1183.         }
  1184.         if (idstr == line)
  1185.           {
  1186.           ShowWarn(msgNoIdentifier);
  1187.           break;
  1188.           }
  1189.  
  1190.         if(!(newidstr = malloc(line-idstr+1)))
  1191.           {
  1192.           MemError();
  1193.           }
  1194.  
  1195.         strncpy(newidstr, idstr, line-idstr);
  1196.         newidstr[line-idstr] = '\0';
  1197.         OverSpace(&line);
  1198.  
  1199.         if(*line)
  1200.           {
  1201.           ShowWarn(msgExtraCharacters);
  1202.           }
  1203.  
  1204.         if((newstr = ReadLine(fp, FALSE)))
  1205.           {
  1206.           for(cs = FirstCatString;  cs != NULL;  cs = cs->Next)
  1207.             {
  1208.             if(strcmp(cs->ID_Str, newidstr) == 0)
  1209.               {
  1210.               break;
  1211.               }
  1212.             }
  1213.           if(cs == NULL)
  1214.             {
  1215.             ShowWarn(msgUnknownIdentifier, newidstr);
  1216.             }
  1217.           else
  1218.             {
  1219.             char *oldstr;
  1220.             char bytes[10];
  1221.             int bytesread, reallen;
  1222.  
  1223.             if(cs->CT_Str)
  1224.               {
  1225.               ShowWarn(msgDoubleIdentifier);
  1226.               Result = FALSE;
  1227.               free(cs->CT_Str);
  1228.               }
  1229.             cs->CT_Str = AllocString(newstr);
  1230.             cs->NotInCT = FALSE;
  1231.  
  1232.             /*
  1233.                 Get stringlen
  1234.             */
  1235.             oldstr = cs->CT_Str;
  1236.             reallen = 0;
  1237.             while(*oldstr)
  1238.               {
  1239.               bytesread = ReadChar(&oldstr, bytes);
  1240.               if(bytesread == 2)
  1241.                 {
  1242.                 bytesread--;
  1243.                 }
  1244.               reallen += bytesread;
  1245.               }
  1246.  
  1247.             if(cs->MinLen > 0  &&  reallen < cs->MinLen)
  1248.               {
  1249.               ShowWarn(msgShortString);
  1250.               }
  1251.             if(cs->MaxLen > 0  &&  reallen > cs->MaxLen)
  1252.               {
  1253.               ShowWarn(msgLongString);
  1254.               }
  1255.  
  1256.  
  1257.             // checking for trailing ellipsis...
  1258.  
  1259.             if( reallen >= 3 )
  1260.                {
  1261.                long cd_len = strlen( cs->CD_Str );
  1262.  
  1263.                if( cd_len >= 3 )
  1264.                    {
  1265.                    if( strcmp( &cs->CD_Str[ cd_len - 3 ], "..." ) == 0 )
  1266.                        if( strcmp( &cs->CT_Str[ reallen - 3 ], "..." ) != 0 )
  1267.                          ShowWarn(msgTrailingEllipsis);
  1268.                    }
  1269.                }    
  1270.  
  1271.  
  1272.             // checking for trailing spaces
  1273.  
  1274.             if( reallen >= 1 )
  1275.                {
  1276.                long cd_len = strlen( cs->CD_Str );
  1277.  
  1278.                if( cd_len >= 1 )
  1279.                    {
  1280.                    if( strcmp( &cs->CD_Str[ cd_len - 1 ], " " ) == 0 )
  1281.                        if( strcmp( &cs->CT_Str[ reallen - 1 ], " " ) != 0 )
  1282.                          ShowWarn(msgTrailingSpaces);
  1283.                    }
  1284.                }
  1285.  
  1286.  
  1287.             }
  1288.           free(newstr);
  1289.           }
  1290.         else
  1291.           {
  1292.           ShowWarn(msgNoString);
  1293.           if(cs)
  1294.               cs->CT_Str = "";
  1295.           }
  1296.         free(newidstr);
  1297.     }
  1298.     free(newline);
  1299.   }
  1300.  
  1301.   fclose(fp);
  1302.  
  1303.   if (WarnCTGaps)
  1304.   { for (cs = FirstCatString;  cs != NULL;  cs = cs->Next)
  1305.     { if (cs->CT_Str == NULL)
  1306.       { ShowWarn(msgCTGap, cs->ID_Str);
  1307.       }
  1308.     }
  1309.   }
  1310.  
  1311.   if(Result)
  1312.     CT_Scanned = TRUE;
  1313.  
  1314.   return(Result);
  1315. }
  1316. //|
  1317. /// FUNC: CatPuts
  1318.  
  1319.  
  1320. /*
  1321.     CatPuts prints a string to a catalog. (The string is preceded by a
  1322.     long integer containing its length and probably padded up to word
  1323.     boundary or longword boundary, depending on the argument padbytes.)
  1324.     The arguments countnul should be TRUE if the NUL byte at the end of
  1325.     the string should be counted.
  1326. */
  1327. int CatPuts(FILE *fp, char *str, int padbytes, int countnul)
  1328. {
  1329.   unsigned long reallen, virtuallen, chunklen;
  1330.   int bytesread;
  1331.   char *oldstr;
  1332.   char bytes[10];
  1333.  
  1334.   /*      Get Length of string.
  1335.   */
  1336.  
  1337.   oldstr = str;
  1338.   reallen = 0;
  1339.  
  1340.   while(*oldstr)
  1341.     {
  1342.     bytesread = ReadChar(&oldstr, bytes);
  1343.     if(bytesread == 2)
  1344.       {
  1345.       bytesread--;
  1346.       }
  1347.     reallen += bytesread;
  1348.     }
  1349.  
  1350.   virtuallen = chunklen = reallen + LengthBytes;
  1351.   if(countnul || chunklen % padbytes == 0)
  1352.     {
  1353.     virtuallen++;
  1354.     }
  1355.  
  1356.   fwrite(&virtuallen, sizeof(virtuallen), 1, fp);
  1357.   if(LengthBytes)
  1358.     {
  1359.     fwrite(((char *) &reallen)+sizeof(reallen)-LengthBytes, LengthBytes, 1, fp);
  1360.     }
  1361.  
  1362.   while(*str)
  1363.     {
  1364.     bytesread = ReadChar(&str, bytes);
  1365.     if(bytesread)
  1366.       {
  1367.       fwrite(bytes+bytesread-1, 1, 1, fp);
  1368.       }
  1369.     }
  1370.  
  1371.   do
  1372.     {
  1373.     putc('\0', fp);
  1374.     }
  1375.   while(++chunklen % padbytes);
  1376.  
  1377.   return((int) chunklen+4);
  1378. }
  1379. //|
  1380. /// FUNC: PutCatalogChunk
  1381.  
  1382. /*
  1383.     This puts a string chunk into the catalog
  1384. */
  1385. int PutCatalogChunk(FILE *fp, struct CatalogChunk *cc)
  1386. {
  1387.   fwrite(&cc->ID, sizeof(cc->ID), 1, fp);
  1388.   return(4 + CatPuts(fp, cc->ChunkStr, 2, TRUE));
  1389. }
  1390. //|
  1391. /// FUNC: CalcRealLength
  1392. /*
  1393.     This function measures the real (binary) length of source
  1394.     string. It correctly process 'slash chars' (\n, \000 etc),
  1395.     and gives the real length such source string have.
  1396.  
  1397.     Inputs: source - pointer to null terminated source string
  1398.  
  1399.     Result: real length
  1400. */
  1401.  
  1402. int CalcRealLength(char *source)
  1403. {
  1404. int  count = 0;
  1405. char *src = source;
  1406. char bytes[10];
  1407.  
  1408.   while(*src)
  1409.     {
  1410.     count += ReadChar(&src, bytes);
  1411.     }
  1412.  
  1413. //  printf("%ld: '%s'\n", count, source);
  1414.  
  1415.   return(count);
  1416.  
  1417. }
  1418. //|
  1419.  
  1420. /// FUNC: CreateCatalog
  1421.  
  1422. /*
  1423.     This creates a catalog.
  1424. */
  1425. void CreateCat(char *CatFile)
  1426. {
  1427.   FILE *fp;
  1428.   int CatLen, HeadLen;
  1429.   struct CatString *cs;
  1430.   struct CatalogChunk *cc;
  1431.   int i;
  1432.  
  1433.   if(!CatVersionString && !CatRcsId)
  1434.     {
  1435.     ShowError(msgNoCTVersion);
  1436.     }
  1437.  
  1438.   if(!CatLanguage)
  1439.     {
  1440.     ShowError(msgNoCTLanguage);
  1441.     }
  1442.  
  1443.   if(strlen(CatLanguage) == 0)
  1444.     {
  1445.     ShowError(msgNoCTLanguage);
  1446.     }
  1447.  
  1448.   if(!(fp = fopen(CatFile, "w")))
  1449.     {
  1450.     ShowError(msgNoCatalog, CatFile);
  1451.     }
  1452.  
  1453.   if(!NoBufferedIO)
  1454.     setvbuf(fp, NULL, _IOFBF, buffer_size);
  1455.  
  1456.  
  1457.   fputs("FORM0000CTLG", fp);
  1458.   CatLen = 4;
  1459.   if(CatVersionString)
  1460.     {
  1461.     struct CatalogChunk cc;
  1462.  
  1463.     cc.ID = 'FVER';
  1464.  
  1465.     if(strstr(CatVersionString, "$TODAY"))
  1466.        {
  1467.        char *verStr;
  1468.  
  1469.        if(verStr = malloc(strlen(CatVersionString)+128))
  1470.            {
  1471.            char *found = strstr(CatVersionString, "$TODAY");
  1472.            char dateStr[10];
  1473.  
  1474.            long tim;
  1475.            struct tm *t;
  1476.  
  1477.            time(&tim);
  1478.            t = gmtime(&tim);
  1479.  
  1480.            *found = 0;
  1481.            strftime(dateStr, sizeof(dateStr), "%d.%m.%y", t);
  1482.  
  1483.            sprintf(verStr, "%s%s%s", CatVersionString, dateStr, found+strlen("$TODAY"));
  1484.            cc.ChunkStr = verStr;
  1485.  
  1486.            free(verStr);
  1487.            }
  1488.        else
  1489.           MemError();
  1490.  
  1491.        }
  1492.     else
  1493.        {
  1494.        cc.ChunkStr = CatVersionString;
  1495.        }
  1496.  
  1497.     CatLen += PutCatalogChunk(fp, &cc);
  1498.     }
  1499.   else
  1500.     {
  1501.     struct CatalogChunk cc;
  1502.     char* verStr;
  1503.     int year = 0, month = 0, day = 0;
  1504.     int version = 0, revision = 0;
  1505.     char* name = NULL;
  1506.     char* ptr;
  1507.  
  1508.     if(!CatRcsId)
  1509.       {
  1510.       ShowError(msgNoCTVersion);
  1511.       }
  1512.     else
  1513.       {
  1514.       if(!(ptr = strstr(CatRcsId, "$Date:"))
  1515.           || sscanf(ptr+6, " %d/%d/%d", &year, &month, &day) != 3
  1516.           || !(ptr = strstr(CatRcsId, "$Revision:"))
  1517.           || sscanf(ptr+10, " %d.%d", &version, &revision) != 2)
  1518.       {
  1519.       ShowError(msgWrongRcsId);
  1520.       }
  1521.       if ((ptr = strstr(CatRcsId, "$Id:")))
  1522.       { int len = 0;
  1523.         char* found;
  1524.  
  1525.         ptr += 4;
  1526.         OverSpace(&ptr);
  1527.         found = ptr;
  1528.  
  1529.         while(*ptr  &&  *ptr != '$'  &&  *ptr != ' '  &&  *ptr != '\t')
  1530.           {
  1531.           ++len;
  1532.           ++ptr;
  1533.           }
  1534.         if(!(name = malloc(len+1)))
  1535.           {
  1536.           MemError();
  1537.          }
  1538.         strncpy(name, found, len);
  1539.         name[len] = '\0';
  1540.       }
  1541.     }
  1542.     if (CatName)
  1543.     { name = CatName;
  1544.     }
  1545.     else if (!name)
  1546.       {
  1547.       ShowError(msgNoCTVersion);
  1548.       name = "";
  1549.       }
  1550.     if (!(verStr = malloc(strlen(name) + 256)))
  1551.       {
  1552.       MemError();
  1553.       }
  1554.     sprintf(verStr, "$V");
  1555.     sprintf(verStr, "ER: %s %d.%d (%d.%d.%d)", name, version, revision, day, month, year);
  1556.     cc.ID = 'FVER';
  1557.     cc.ChunkStr = verStr;
  1558.     CatLen += PutCatalogChunk(fp, &cc);
  1559.   }
  1560.   for (cc = FirstChunk;  cc != NULL;  cc = cc->Next)
  1561.   { CatLen += PutCatalogChunk(fp, cc);
  1562.   }
  1563.   i = 32;
  1564.   fputs("CSET", fp);
  1565.   fwrite(&i, sizeof(i), 1, fp);
  1566.   while(i-- > 0)
  1567.   { putc('\0', fp);
  1568.   }
  1569.   CatLen += 48;
  1570.   fprintf(fp, "STRS0000");
  1571.   HeadLen = CatLen;
  1572.  
  1573.  
  1574.   for(cs = FirstCatString;  cs != NULL;  cs = cs->Next)
  1575.     {
  1576.     int FillUsed = FALSE;
  1577.  
  1578.     if(Fill)
  1579.       {
  1580.       if(cs->CT_Str)
  1581.         {
  1582.         if(strlen(cs->CT_Str) == 0)
  1583.           {
  1584.           fwrite(&cs->ID, sizeof(cs->ID), 1, fp);
  1585.           CatLen += 4 + CatPuts(fp, cs->CD_Str, 4, FALSE);
  1586.           FillUsed = TRUE;
  1587.           }
  1588.         }
  1589.       else
  1590.         {
  1591.         fwrite(&cs->ID, sizeof(cs->ID), 1, fp);
  1592.         CatLen += 4 + CatPuts(fp, cs->CD_Str, 4, FALSE);
  1593.         FillUsed = TRUE;
  1594.         }
  1595.       }
  1596.  
  1597.     if((!FillUsed) && cs->CT_Str  &&  (NoOptim ? TRUE : strcmp(cs->CT_Str, cs->CD_Str)))
  1598.       {
  1599.       fwrite(&cs->ID, sizeof(cs->ID), 1, fp);
  1600.       CatLen += 4 + CatPuts(fp, cs->CT_Str, 4, FALSE);
  1601.       }
  1602.     }
  1603.  
  1604.   fseek(fp, 4, SEEK_SET);
  1605.   fwrite(&CatLen, sizeof(CatLen), 1, fp);
  1606.   fseek(fp, HeadLen-4, SEEK_CUR);
  1607.   CatLen -= HeadLen;
  1608.   fwrite(&CatLen, sizeof(CatLen), 1, fp);
  1609.   fclose(fp);
  1610.  
  1611.   Expunge();
  1612.  
  1613. }
  1614. //|
  1615. /// FUNC: CreateCTFile
  1616.  
  1617. /*
  1618.     This creates a new catalog translation file.
  1619. */
  1620. void CreateCTFile(char *NewCTFile)
  1621. {
  1622.   FILE   *fp;
  1623.   struct CDLine *cd;
  1624.   struct CatString *cs;
  1625.   struct CatalogChunk *cc;
  1626.   char   *line;
  1627.  
  1628.   if(!CatVersionString && !CatRcsId)
  1629.     {
  1630.     ScanLine = 1;
  1631.     ShowWarn(msgNoCTVersion);
  1632.     }
  1633.  
  1634.   if(!(fp = fopen(NewCTFile, "w")))
  1635.     {
  1636.     ShowError(msgNoNewCTFile);
  1637.     }
  1638.  
  1639.  
  1640.   if(!NoBufferedIO)
  1641.     setvbuf(fp, NULL, _IOFBF, buffer_size);
  1642.  
  1643.  
  1644.   if(CatRcsId)
  1645.     {
  1646.     fprintf(fp, "## rcsid %s\n",
  1647.           CatRcsId ? CatRcsId : "");
  1648.     if(CatName)
  1649.        fprintf(fp, "## name %s\n", CatName);
  1650.     }
  1651.   else
  1652.     {
  1653.     if(CatVersionString)
  1654.       fprintf(fp, "## version %s\n", CatVersionString);
  1655.     else
  1656.       {
  1657.       fprintf(fp, "## version $V");
  1658.       fprintf(fp, "%c", 50+19);  // E
  1659.       fprintf(fp, "R: XX.catalog XX.XX ($TODAY)\n");
  1660.       }
  1661.     }
  1662.  
  1663.  
  1664.   {
  1665.   char *lang = NULL;
  1666.  
  1667.   if(CatLanguage == NULL)
  1668.     if(lang = getenv("ENV:language"))
  1669.       {
  1670.       int i;
  1671.  
  1672.       for(i=0;i<strlen(lang); i++)
  1673.         if(lang[i] == '\n')
  1674.           {
  1675.           lang[i] = 0;
  1676.           break;
  1677.           }
  1678.  
  1679.       CatLanguage = lang;
  1680.       }
  1681.  
  1682.   fprintf(fp, "## language %s\n## codeset %d\n;\n",
  1683.        CatLanguage ? CatLanguage : "X", CodeSet);
  1684.  
  1685.   if(lang)
  1686.     {
  1687.     free(lang);
  1688.     CatLanguage = NULL;
  1689.     }
  1690.   }
  1691.  
  1692.  
  1693.  
  1694.   for (cc = FirstChunk;  cc != NULL;  cc = cc->Next)
  1695.     {
  1696.     if (cc->ChunkStr != CatLanguage)
  1697.       {
  1698.       fprintf(fp, "## chunk ");
  1699.       fwrite((char *) &cc->ID, sizeof(cc->ID), 1, fp);
  1700.       fprintf(fp, " %s\n", cc->ChunkStr);
  1701.       }
  1702.     }
  1703.  
  1704.   for(cd = FirstCDLine, cs = FirstCatString;
  1705.       cd != NULL;
  1706.       cd = cd->Next)
  1707.      {
  1708.      switch(*cd->Line)
  1709.        {
  1710.        case '#':
  1711.           break;
  1712.  
  1713.        case ';':
  1714.           fprintf(fp, "%s\n", cd->Line);
  1715.           break;
  1716.  
  1717.        default:
  1718.           if(cs)
  1719.             {
  1720. /*
  1721.             fprintf(fp, "%s\n", cs->ID_Str);
  1722.             fprintf(fp, "%s\n", cs->CT_Str ? cs->CT_Str : "");
  1723.             putc(';', fp);
  1724.             putc(' ', fp);
  1725. */
  1726.             fprintf(fp, "%s\n%s\n; ", cs->ID_Str, cs->CT_Str ? cs->CT_Str : "");
  1727.  
  1728.  
  1729.  
  1730.             for (line = cs->CD_Str;  *line;  ++line)
  1731.               {
  1732.               putc((int) *line, fp);
  1733.               if(*line == '\n')
  1734.                 {
  1735.                 putc(';', fp);
  1736.                 putc(' ', fp);
  1737.                 }
  1738.               }
  1739.             putc('\n', fp);
  1740.  
  1741.             if(cs->NotInCT && CT_Scanned)
  1742.               fprintf(fp, ";\n; %s\n", Msg_New);
  1743.  
  1744.             cs = cs->Next;
  1745.             }
  1746.        }
  1747.      }
  1748.  
  1749.   fclose(fp);
  1750. }
  1751. //|
  1752.  
  1753. /// FUNC: InitCatStringOutput
  1754.  
  1755. /*
  1756.     InitCatStringOutput gets called before writing a catalog string as
  1757.     source.
  1758.  
  1759.     Inputs: fp   = file pointer to the output file
  1760.             type = one of   TYPE_C          create C strings
  1761.                             TYPE_ASSEMBLER  create Assembler strings
  1762.                             TYPE_OBERON     create Oberon strings
  1763.                             TYPE_E          create E strings
  1764.                             TYPE_NONE       create simple strings
  1765. */
  1766. int  OutputMode = OutputMode_None;
  1767. int  OutputType = TYPE_C;
  1768. FILE *OutputFile;
  1769. int  OutputLen;
  1770.  
  1771. void InitCatStringOutput(FILE *fp)
  1772. {
  1773.   OutputLen = 0;
  1774.   OutputFile = fp;
  1775.   OutputMode = OutputMode_None;
  1776.   switch(OutputType)
  1777.   { case TYPE_C:
  1778.     case TYPE_OBERON:
  1779.       putc('\"', fp);
  1780.       OutputMode = OutputMode_Ascii;
  1781.       break;
  1782.     case TYPE_E:
  1783.       putc('\'', fp);
  1784.     case TYPE_ASSEMBLER:
  1785.     case TYPE_NONE:
  1786.       break;
  1787.   }
  1788. }
  1789. //|
  1790. /// FUNC: SeparateCatStringOutput
  1791.  
  1792. /*
  1793.     SeparateCatStringOutput gets called to split a catalog into separate
  1794.     lines.
  1795. */
  1796. void SeparateCatStringOutput(void)
  1797. {
  1798.     switch(OutputType)
  1799.     { case TYPE_C:
  1800.         if (!LongStrings)
  1801.         { fputs("\"\\\n\t\"", OutputFile);
  1802.         }
  1803.         break;
  1804.       case TYPE_E:
  1805.         if (!LongStrings)
  1806.         { fputs("\' +\n\t\'", OutputFile);
  1807.         }
  1808.         break;
  1809.       case TYPE_OBERON:
  1810.         if (!LongStrings)
  1811.         { fputs("\"\n\t\"", OutputFile);
  1812.         }
  1813.         break;
  1814.       case TYPE_ASSEMBLER:
  1815.         if (!LongStrings)
  1816.         { if (OutputMode == OutputMode_Ascii)
  1817.           { putc('\'', OutputFile);
  1818.           }
  1819.           putc('\n', OutputFile);
  1820.           OutputMode = OutputMode_None;
  1821.         }
  1822.         break;
  1823.       case TYPE_NONE:
  1824.         break;
  1825.     }
  1826. }
  1827. //|
  1828. /// FUNC: WriteBinChar
  1829.  
  1830. /*
  1831.     WriteBinChar writes one binary character into the source file
  1832. */
  1833. void WriteBinChar(int c)
  1834. {
  1835.  
  1836.   switch(OutputType)
  1837.   { case TYPE_C:
  1838.     case TYPE_E:
  1839.     case TYPE_OBERON:
  1840.       switch(c)
  1841.       { case '\b':
  1842.           fputs("\\b", OutputFile);
  1843.           break;
  1844.         case '\n':
  1845.           fputs("\\n", OutputFile);
  1846.           break;
  1847.         case '\r':
  1848.           fputs("\\r", OutputFile);
  1849.           break;
  1850.         case '\t':
  1851.           fputs("\\t", OutputFile);
  1852.           break;
  1853.         case '\f':
  1854.           fputs("\\f", OutputFile);
  1855.           break;
  1856.         case '\0':
  1857.           fputs("\\000", OutputFile);
  1858.           break;
  1859.         default:
  1860.           if(OutputType == TYPE_E  &&  c == '\033')
  1861.             {
  1862.             fputs("\\e", OutputFile);
  1863.             }
  1864.           else
  1865.            {
  1866.            fprintf(OutputFile, "\\%c%c%c", ((c >> 6) & 3) + '0',
  1867.                     ((c >> 3) & 7) + '0', (c & 7) + '0');
  1868.            }
  1869.           break;
  1870.       }
  1871.       ++OutputLen;
  1872.       OutputMode = OutputMode_Bin;
  1873.       break;
  1874.     case TYPE_ASSEMBLER:
  1875.       switch(OutputMode)
  1876.       { case OutputMode_None:
  1877.           fprintf(OutputFile, "\tdc.b\t$%02x", c & 0xff);
  1878.           break;
  1879.         case OutputMode_Ascii:
  1880.           putc('\'', OutputFile);
  1881.         case OutputMode_Bin:
  1882.           fprintf(OutputFile, ",$%02x", c & 0xff);
  1883.           break;
  1884.       }
  1885.       ++OutputLen;
  1886.       OutputMode = OutputMode_Bin;
  1887.       break;
  1888.     case TYPE_NONE:
  1889.       ShowWarn(msgNoBinChars);
  1890.       break;
  1891.   }
  1892. }
  1893. //|
  1894. /// FUNC: WriteAsciiChar
  1895.  
  1896. /*
  1897.     WriteAsciiChar writes one ascii character into the source file.
  1898. */
  1899. void WriteAsciiChar(int c)
  1900. {
  1901.  
  1902.   switch(OutputType)
  1903.   { case TYPE_C:
  1904.     case TYPE_OBERON:
  1905.       switch(c)
  1906.       { case '\"':
  1907.           fputs("\\\"", OutputFile);
  1908.           break;
  1909.         default:
  1910.           putc(c, OutputFile);
  1911.           break;
  1912.       }
  1913.       ++OutputLen;
  1914.       OutputMode = OutputMode_Ascii;
  1915.       break;
  1916.     case TYPE_E:
  1917.       switch(c)
  1918.       { case '\'':
  1919.           fputs("''", OutputFile);
  1920.           break;
  1921.         default:
  1922.           putc(c, OutputFile);
  1923.           break;
  1924.       }
  1925.       ++OutputLen;
  1926.       OutputMode = OutputMode_Ascii;
  1927.       break;
  1928.     case TYPE_ASSEMBLER:
  1929.       if (c == '\'')
  1930.       { WriteBinChar(c);
  1931.       }
  1932.       else
  1933.       { switch (OutputMode)
  1934.         { case OutputMode_None:
  1935.             fprintf(OutputFile, "\tdc.b\t\'%c", c);
  1936.             break;
  1937.           case OutputMode_Ascii:
  1938.             putc(c, OutputFile);
  1939.             break;
  1940.           case OutputMode_Bin:
  1941.             fprintf(OutputFile, ",\'%c", c);
  1942.             break;
  1943.         }
  1944.         ++OutputLen;
  1945.         OutputMode = OutputMode_Ascii;
  1946.       }
  1947.       break;
  1948.     case TYPE_NONE:
  1949.       putc(c, OutputFile);
  1950.       break;
  1951.   }
  1952. }
  1953. //|
  1954. /// FUNC: TerminateCatStringOutput
  1955.  
  1956. /*
  1957.     TerminateCatStringOutput finishs the output of a catalog string.
  1958. */
  1959. void TerminateCatStringOutput(void)
  1960. {
  1961.   switch(OutputType)
  1962.   { case TYPE_C:
  1963.     case TYPE_OBERON:
  1964.       putc('\"', OutputFile);
  1965.       break;
  1966.     case TYPE_E:
  1967.       putc('\'', OutputFile);
  1968.       break;
  1969.     case TYPE_ASSEMBLER:
  1970.       switch(OutputMode)
  1971.       { case OutputMode_Ascii:
  1972.           putc('\'', OutputFile);
  1973.         case OutputMode_Bin:
  1974.           break;
  1975.         case OutputMode_None:
  1976.           break;
  1977.       }
  1978.     case TYPE_NONE:
  1979.       break;
  1980.   }
  1981. }
  1982. //|
  1983.  
  1984. /// FUNC: WriteString
  1985. /*
  1986.     This writes a sourcestring.
  1987. */
  1988. void WriteString(FILE *fpout, char *str, long Len)
  1989. {
  1990.   char bytes[10];
  1991.   int bytesread;
  1992.   int needseparate = FALSE;
  1993.  
  1994.   InitCatStringOutput(fpout);
  1995.   if (Len >= 0)
  1996.   { int i;
  1997.  
  1998.     for(i = LengthBytes;  i >= 1;  i--)
  1999.     { WriteBinChar((int) ((char *) &Len)[sizeof(Len)-i]);
  2000.     }
  2001.   }
  2002.  
  2003.   while (*str)
  2004.   { bytesread = ReadChar(&str, bytes);
  2005.     if (bytesread)
  2006.     { unsigned char c;
  2007.  
  2008.       if (needseparate)
  2009.       { SeparateCatStringOutput();
  2010.         needseparate = FALSE;
  2011.       }
  2012.  
  2013.       c = bytes[bytesread-1];
  2014.       if ((c >= 0x20  &&  c < 0x7f)  ||  c >= 0xa0)
  2015.       { WriteAsciiChar((int) c);
  2016.       }
  2017.       else
  2018.       { WriteBinChar((int) c);
  2019.       }
  2020.     }
  2021.     else
  2022.     { needseparate = TRUE;
  2023.     }
  2024.   }
  2025.   TerminateCatStringOutput();
  2026. }
  2027. //|
  2028. /// FUNC: AllocFileName
  2029. /*
  2030.     This function creates a copy of a filename, removes an
  2031.     optional ending and pathname components, if desired.
  2032.  
  2033.     Inputs: filename - the filename to copy
  2034.             howto - a set of bits
  2035.                         bit 0: 1 = remove ending, 0 = leave it
  2036.                         bit 1: 1 = remove pathname, 0 = leave it
  2037.  
  2038.     Result: The copy of the filename
  2039. */
  2040. char *AllocFileName(char *filename, int howto)
  2041. {
  2042.   char *tempstr, *ptr;
  2043.  
  2044.   if (!(tempstr = strdup(filename)))
  2045.   { MemError();
  2046.     MyExit(10);
  2047.   }
  2048.  
  2049.   /*  Remove pathname components, if desired    */
  2050.   if (howto & 2)
  2051.   { if ((ptr = strchr(tempstr, ':')))
  2052.     { tempstr = ptr+1;
  2053.     }
  2054.     if ((ptr = strrchr(tempstr, '/')))
  2055.     { tempstr = ptr+1;
  2056.     }
  2057.   }
  2058.  
  2059.   /*  Remove ending, if desired.                */
  2060.   if (howto & 1)
  2061.   { if ((ptr = strrchr(tempstr, '.')))
  2062.     { *ptr = '\0';
  2063.     }
  2064.   }
  2065.  
  2066.   return(tempstr);
  2067. }
  2068. //|
  2069. /// FUNC: AddFileName
  2070. /*
  2071.     This function adds a pathname and a filename to a full
  2072.     filename.
  2073.  
  2074.     Inputs: pathname - the leading pathname
  2075.             filename - the filename
  2076.  
  2077.     Result: The new filename
  2078. */
  2079. char *AddFileName(char *pathname, char *filename)
  2080. {
  2081.   char *buffer;
  2082.   int size = strlen(pathname) + strlen(filename) + 2;
  2083.  
  2084.   if (!(buffer = malloc(size)))
  2085.   { MemError();
  2086.     MyExit(10);
  2087.   }
  2088.  
  2089. #if defined(__amigados)
  2090.   strcpy(buffer, pathname);
  2091.   AddPart((STRPTR) buffer, (STRPTR) filename, size);
  2092. #else
  2093.   sprintf(buffer, "%s/%s", pathname, filename);
  2094. #endif
  2095.  
  2096.   return(buffer);
  2097. }
  2098. //|
  2099.  
  2100. /// FUNC: CreateSourceFile
  2101.  
  2102. /*
  2103.     Finally the source creation.
  2104. */
  2105. void CreateSourceFile(char *SourceFile, char *TemplateFile, char *CDFile)
  2106. {
  2107.  
  2108.   FILE *fpin, *fpout;
  2109.   char *line;
  2110.   char *OrigTemplateFile = TemplateFile;
  2111.  
  2112.   ScanFile = SourceFile;
  2113.   ScanLine = 0;
  2114.  
  2115.   /*
  2116.     Open the source file. This may be found in various places
  2117.   */
  2118.   if(!(fpin = fopen(TemplateFile, "r")))
  2119.     {
  2120. #ifdef __amigados
  2121.     if(*prefs_sddir != 0)
  2122.       {
  2123.       TemplateFile = AddFileName(prefs_sddir, OrigTemplateFile);
  2124.       fpin = fopen(TemplateFile, "r");
  2125.       }
  2126. #endif
  2127.     }
  2128.  
  2129.   if(!fpin)
  2130.     {
  2131.     char *sddir;
  2132.  
  2133.     if((sddir = getenv(FLEXCAT_SDDIR)))
  2134.       {
  2135.       TemplateFile = AddFileName(sddir, OrigTemplateFile);
  2136.       fpin = fopen(TemplateFile, "r");
  2137.       }
  2138.     }
  2139.  
  2140.   if (!fpin)
  2141.   { TemplateFile = AddFileName(DEFAULT_FLEXCAT_SDDIR, OrigTemplateFile);
  2142.     fpin = fopen(TemplateFile, "r");
  2143.   }
  2144.  
  2145.   if (!fpin)
  2146.     {
  2147.       ShowError(msgNoSourceDescription, OrigTemplateFile);
  2148.       return;
  2149.     }
  2150.  
  2151.   if (!(fpout = fopen(SourceFile, "w")))
  2152.   {
  2153.     ShowError(msgNoSource, SourceFile);
  2154.     return;
  2155.   }
  2156.  
  2157.   if(!NoBufferedIO)
  2158.     setvbuf(fpin, NULL, _IOFBF, buffer_size);
  2159.   if(!NoBufferedIO)
  2160.     setvbuf(fpout, NULL, _IOFBF, buffer_size);
  2161.  
  2162.  
  2163.   while(!feof(fpin)  &&  (line = ReadLine(fpin, FALSE)))
  2164.   { struct CatString *cs;
  2165.     int NeedRepeat;
  2166.     char bytes[10];
  2167.     int bytesread;
  2168.  
  2169.     cs = FirstCatString;
  2170.     do
  2171.     { char *currentline = line;
  2172.       NeedRepeat = FALSE;
  2173.  
  2174.       if (*currentline == '#'  &&  *(++currentline) == '#')
  2175.       { ++currentline;
  2176.         OverSpace(¤tline);
  2177.         if (strnicmp(currentline, "stringtype", 10) == 0)
  2178.         { currentline += 10;
  2179.           OverSpace(¤tline);
  2180.           if (strnicmp(currentline, "c", 1) == 0)
  2181.           { OutputType = TYPE_C;
  2182.             ++currentline;
  2183.           }
  2184.           else if (strnicmp(currentline, "assembler", 9) == 0)
  2185.           { OutputType = TYPE_ASSEMBLER;
  2186.             currentline += 9;
  2187.           }
  2188.           else if (strnicmp(currentline, "oberon", 6) == 0)
  2189.           { OutputType = TYPE_OBERON;
  2190.             currentline += 6;
  2191.           }
  2192.           else if (strnicmp(currentline, "e", 1)  ==  0)
  2193.           { OutputType = TYPE_E;
  2194.             ++currentline;
  2195.           }
  2196.           else if (strnicmp(currentline, "none", 4)  ==  0)
  2197.           { OutputType = TYPE_NONE;
  2198.             currentline += 4;
  2199.           }
  2200.           else
  2201.           { ShowWarn(msgUnknownStringType);
  2202.             currentline += strlen(currentline);
  2203.           }
  2204.           OverSpace(¤tline);
  2205.           if (*currentline)
  2206.           { ShowWarn(msgExtraCharacters);
  2207.           }
  2208.           continue;
  2209.         }
  2210.         else if (strnicmp(currentline, "shortstrings", 12) == 0)
  2211.         { currentline += 12;
  2212.           LongStrings = FALSE;
  2213.           OverSpace(¤tline);
  2214.           if (*currentline)
  2215.           { ShowWarn(msgExtraCharacters);
  2216.           }
  2217.           continue;
  2218.         }
  2219.       }
  2220.  
  2221.       currentline = line;
  2222.       while(*currentline)
  2223.       { bytesread = ReadChar(¤tline, bytes);
  2224.         if (bytesread)
  2225.         { if (*bytes == '%')
  2226.           { char c;
  2227.  
  2228.             switch(c = *(currentline++))
  2229.             { case 'b':
  2230.                 fputs(BaseName, fpout);
  2231.                 break;
  2232.               case 'n':
  2233.                 fprintf(fpout, "%d", NumStrings);
  2234.                 break;
  2235.               case 'v':
  2236.                 fprintf(fpout, "%d", CatVersion);
  2237.                 break;
  2238.               case 'l':
  2239.                 WriteString(fpout, Language, -1);
  2240.                 break;
  2241.               case 'f':
  2242.                 { char *tempstr;
  2243.  
  2244.                   if ((c = *currentline++) == 'v')
  2245.                   { fputs(VERS, fpout);
  2246.                   }
  2247.                   else
  2248.                   { tempstr = AllocFileName(CDFile, c - '0');
  2249.                     fputs(tempstr, fpout);
  2250.                   }
  2251.                 }
  2252.                 break;
  2253.               case 'o':
  2254.                 { char *tempstr;
  2255.  
  2256.                   tempstr = AllocFileName(SourceFile, *currentline++ - '0');
  2257.                   fputs(tempstr, fpout);
  2258.                 }
  2259.                 break;
  2260.               case 'i':
  2261.                 NeedRepeat = TRUE;
  2262.                 if (cs) fputs(cs->ID_Str, fpout);
  2263.                 break;
  2264.  
  2265.               case 'a':
  2266.               case 't':
  2267.  
  2268.               case 'd':
  2269.               case 'x':
  2270.               case 'c':
  2271.               case '0':
  2272.               case '1':
  2273.               case '2':
  2274.               case '3':
  2275.               case '4':
  2276.               case '5':
  2277.               case '6':
  2278.               case '7':
  2279.               case '8':
  2280.               case '9':
  2281.                   {
  2282.                   int len = 0;
  2283.  
  2284.                   while(c >= '0'  &&  c <= '9')
  2285.                     {
  2286.                     len = (c - '0') + len * 10;
  2287.                     c = *currentline++;
  2288.                     }
  2289.  
  2290.  
  2291.                   if(c ==  'a')
  2292.                     {
  2293.                     int _len = len ? len : 4;
  2294.                     char *start;
  2295.                     char _StrLen[20 + 1];
  2296.  
  2297.                     sprintf(_StrLen, "%020lx", cs->ID);
  2298.  
  2299.                     start = &_StrLen[20-_len*2];
  2300.                     while(_len>0)
  2301.                        {
  2302.                        fprintf(fpout, "\\x%.2s", start);
  2303.                        start+=2;
  2304.                        _len--;
  2305.                        }
  2306.                     }
  2307.  
  2308.                   if(c ==  't')
  2309.                     {
  2310.                     int _len = len ? len : 4;
  2311.                     char *start;
  2312.                     char _StrLen[20 + 1];
  2313.  
  2314.                     sprintf(_StrLen, "%020lx", ((CalcRealLength(cs->CD_Str) + 1) & 0xfffffe));
  2315.  
  2316.                     start = &_StrLen[20-_len*2];
  2317.                     while(_len>0)
  2318.                        {
  2319.                        fprintf(fpout, "\\x%.2s", start);
  2320.                        start+=2;
  2321.                        _len--;
  2322.                        }
  2323.                     }
  2324.  
  2325.                   if(c == 'c' || c == 'd' || c == 'x')
  2326.                     {
  2327.                     char buffer[20];
  2328.  
  2329.                     if(c == 'c') c = 'o';
  2330.  
  2331.                     if(len)
  2332.                       sprintf(buffer, "%%0%d%c", len, c);
  2333.                     else
  2334.                       sprintf(buffer, "%%%c", c);
  2335.  
  2336.                     if(cs) fprintf(fpout, buffer, cs->ID);
  2337.                     }
  2338.  
  2339.  
  2340.                   NeedRepeat = TRUE;
  2341.                   }
  2342.                   break;
  2343.  
  2344.               case 'e':
  2345.                 NeedRepeat = TRUE;
  2346.                 if (cs) fprintf(fpout, "%d", cs->Nr);
  2347.                 break;
  2348.               case 's':
  2349.                 NeedRepeat = TRUE;
  2350.                 if (cs)
  2351.                 { char *idstr;
  2352.                   unsigned long len = 0;
  2353.  
  2354.                   if (LengthBytes)
  2355.                   { idstr = cs->CD_Str;
  2356.                     while(*idstr)
  2357.                     { bytesread = ReadChar(&idstr, bytes);
  2358.                       if (bytesread)
  2359.                       { ++len;
  2360.                       }
  2361.                     }
  2362.                   }
  2363.                   WriteString(fpout, cs->CD_Str, LengthBytes ? len : -1);
  2364.                 }
  2365.                 break;
  2366.               case '(':
  2367.                 NeedRepeat = TRUE;
  2368.                 while(*currentline  &&  *currentline != ')')
  2369.                 { bytesread = ReadChar(¤tline, bytes);
  2370.                   if (bytesread  &&  cs  &&  cs->Next)
  2371.                   { putc((int) bytes[bytesread-1], fpout);
  2372.                   }
  2373.                 }
  2374.                 if (!*currentline)
  2375.                 { ShowWarn(msgNoTerminateBracket);
  2376.                 }
  2377.                 else
  2378.                 { ++currentline;
  2379.                 }
  2380.                 break;
  2381.  
  2382. // !!!! FIX !!!!
  2383.  
  2384.               case 'z':
  2385.                 {
  2386.                 int diff = (((CalcRealLength(cs->CD_Str) + 1) & 0xfffffe) - (CalcRealLength(cs->CD_Str)));
  2387.  
  2388.                 NeedRepeat = TRUE;
  2389.  
  2390.                 while(diff > 0)
  2391.                    {
  2392.                    fprintf(fpout, "\\x00");
  2393.                    diff--;
  2394.                    }
  2395.  
  2396.                 break;
  2397.                 }
  2398.  
  2399.               default:
  2400.                 { int c = *currentline++;
  2401.  
  2402.                   putc(c, fpout);
  2403.                 }
  2404.             }
  2405.           }
  2406.           else
  2407.           { putc((int) bytes[bytesread-1], fpout);
  2408.           }
  2409.         }
  2410.       }
  2411.       putc('\n', fpout);
  2412.     }
  2413.     while(NeedRepeat  &&  cs  &&  (cs = cs->Next));
  2414.  
  2415.     free(line);
  2416.   }
  2417.  
  2418.   fclose(fpin);
  2419.   fclose(fpout);
  2420. }
  2421. //|
  2422.  
  2423. /// FUNC: Usage
  2424. /*
  2425.     The Usage function describes the programs calling syntax.
  2426. */
  2427. void Usage(void)
  2428.  
  2429. {
  2430.   fputs((char *) msgUsageHead, stderr);
  2431.   fprintf(stderr, ": FlexCat CDFILE/A,CTFILE,CATALOG/K,NEWCTFILE/K,SOURCES/M,\n                WARNCTGAPS/S,NOOPTIM/S,FILL/S,FLUSH/S,NOBEEP/S,\n                QUIET/S,NOLANGTOLOWER/S,NOBUFFEREDIO/S,\n\                MODIFIED/S,COPYMSGNEW/S,OLDMSGNEW/K\n\n", VString);
  2432.   fprintf(stderr, "%s\n%s%s", msgUsage, msgUsage_2, msgUsage_3);
  2433.   fprintf(stderr, "\n\n%s"
  2434. /*
  2435.   #ifdef _M68040
  2436.     " [040]"
  2437.   #else
  2438.     #ifdef _M68060
  2439.       " [060]"
  2440.     #else
  2441.       #ifdef _M68030
  2442.         " [030]"
  2443.       #else
  2444.         #ifdef _M68020
  2445.           " [020]"
  2446.         #else
  2447.           #ifdef _M68010
  2448.             " [010]"
  2449.           #endif
  2450.         #endif
  2451.       #endif
  2452.     #endif
  2453.   #endif
  2454. */
  2455.   "\n", VString);
  2456.  
  2457.  
  2458.   fprintf(stderr, "%s\n", EString);
  2459.   MyExit(5);
  2460. }
  2461. //|
  2462. /// FUNC: main
  2463. /*
  2464.     Finally the main function. Does nothing special except for scanning
  2465.     the arguments.
  2466. */
  2467. int main (int argc, char *argv [])
  2468. {
  2469.   char *cdfile, *ctfile, *newctfile, *catalog;
  2470.   char *source, *template;
  2471.   int i;
  2472.  
  2473.   if(argc == 0)    /*  Aztec's entry point for workbench programs  */
  2474.    {
  2475.    fprintf(stderr, "FlexCat can't be run from Workbench!\n\n");
  2476.    fprintf(stderr, "Open a Shell session and type FlexCat ?\n");
  2477.    fprintf(stderr, "for more information\n");
  2478.    exit(5);
  2479.    }
  2480.  
  2481.   cdfile = ctfile = newctfile = catalog = NULL;
  2482.  
  2483. #if defined(__amigados)
  2484.   ReadPrefs();
  2485. #endif
  2486.  
  2487.   if(argc == 1)
  2488.     {
  2489.     Usage();
  2490.     }
  2491.  
  2492.   for (i = 1;  i < argc;  i++)
  2493.     {
  2494.     if(strnicmp (argv[i], "catalog=", 8) == 0)
  2495.       {
  2496.       catalog = argv[i] + 8;
  2497.       }
  2498.     else
  2499.     if(stricmp (argv[i], "catalog") == 0)
  2500.       {
  2501.       if(i+1 == argc)
  2502.         Usage();
  2503.       catalog = argv[++i];
  2504.       }
  2505.     else
  2506.     if(stricmp(argv[i], "nooptim") == 0)
  2507.      {
  2508.      NoOptim = TRUE;
  2509.      }
  2510.     else
  2511.     if(stricmp(argv[i], "fill") == 0)
  2512.      {
  2513.      Fill = TRUE;
  2514.      }
  2515.     else
  2516.     if(stricmp(argv[i], "quiet") == 0)
  2517.      {
  2518.      Quiet = TRUE;
  2519.      }
  2520.     else
  2521.     if(stricmp(argv[i], "flush") == 0)
  2522.      {
  2523.      DoExpunge = TRUE;
  2524.      }
  2525.     else
  2526.     if(stricmp(argv[i], "nobeep") == 0)
  2527.      {
  2528.      NoBeep = TRUE;
  2529.      }
  2530.     else
  2531.     if(stricmp(argv[i], "nobufferedio") == 0)
  2532.      {
  2533.      NoBufferedIO = TRUE;
  2534.      }
  2535.     else
  2536.     if (strnicmp (argv[i], "newctfile=", 10) == 0)
  2537.       {
  2538.       newctfile = argv[i] + 10;
  2539.       }
  2540.     else
  2541.     if(strnicmp (argv[i], "newctfile", 10) == 0)
  2542.       {
  2543.       if (i+1 == argc)
  2544.         Usage();
  2545.       newctfile = argv[++i];
  2546.       }
  2547.     else
  2548.     if(stricmp(argv[i], "nolangtolower") == 0)
  2549.       {
  2550.       LANGToLower = FALSE;
  2551.       }
  2552.     else
  2553.     if(stricmp(argv[i], "modified") == 0)
  2554.       {
  2555.       Modified = TRUE;
  2556.       }
  2557.     else
  2558.     if(stricmp(argv[i], "warnctgaps") == 0)
  2559.       {
  2560.       WarnCTGaps = TRUE;
  2561.       }
  2562.     else
  2563.     if(stricmp(argv[i], "copymsgnew") == 0)
  2564.       {
  2565.       CopyNEWs = TRUE;
  2566.       }
  2567.     else
  2568.     if(stricmp(argv[i], "oldmsgnew") == 0)
  2569.       {
  2570.       sprintf( Old_Msg_New, "; %s", argv[++i] );
  2571.       }
  2572.     else
  2573.       if(cdfile == NULL)
  2574.         {
  2575.         if(stricmp(argv[i], "?") == 0 || stricmp(argv[i], "-h") == 0 || stricmp(argv[i], "help") == 0 || stricmp(argv[i], "--help") == 0)
  2576.           {
  2577.           Usage();
  2578.           }
  2579.         if(!ScanCDFile(cdfile = argv[i]))
  2580.           {
  2581.           MyExit(10);
  2582.           }
  2583.         }
  2584.     else
  2585.     if(strchr(argv[i], '='))
  2586.       {
  2587.       source = AllocString(argv[i]);
  2588.       *(template = strchr(source, '=')) = '\0';
  2589.       ++template;
  2590.  
  2591.       CreateSourceFile(source, template, cdfile);
  2592.       }
  2593.     else
  2594.       {
  2595.       if (ctfile)
  2596.         {
  2597.         Usage();
  2598.         }
  2599.       ctfile = argv[i];
  2600.       }
  2601.     }
  2602.  
  2603.   if(Modified)
  2604.     {
  2605.     if(cdfile && ctfile && catalog)
  2606.        {
  2607.        long cd_time, ct_time, cat_time;
  2608.  
  2609.        if((cd_time = getft(cdfile)) != -1)
  2610.            {
  2611.            if((ct_time = getft(ctfile)) != -1)
  2612.               {
  2613.               if((cat_time = getft(catalog)) == -1)
  2614.                 cat_time = 0;
  2615.  
  2616.                 if((cat_time > ct_time) &&
  2617.                    (cat_time > cd_time))
  2618.                        {
  2619.                        if(!Quiet)
  2620.                          {
  2621.                          fprintf(stderr, (char *) msgUpToDate, catalog);
  2622.                          putc('\n', stderr);
  2623.                          }
  2624.  
  2625.                        MyExit(GlobalReturnCode);
  2626.                        }
  2627.                   else
  2628.                     {
  2629.                     if(!Quiet)
  2630.                       {
  2631.                       fprintf(stderr, "--> %s", catalog);
  2632.                       putc('\n', stderr);
  2633.                       }
  2634.                     }
  2635.               }
  2636.             else
  2637.               {
  2638.               ShowError(msgCantCheckDate, ctfile);
  2639.               }
  2640.            }
  2641.         else
  2642.            {
  2643.            ShowError(msgCantCheckDate, cdfile);
  2644.            }
  2645.        }
  2646.     }
  2647.  
  2648.  
  2649.   if(ctfile)
  2650.     {
  2651.     if(!ScanCTFile(ctfile))
  2652.       MyExit(10);
  2653.     }
  2654.  
  2655.   if(catalog)
  2656.     {
  2657.     if(!ctfile)
  2658.       {
  2659.       fprintf(stderr, (char *) msgNoCTArgument);
  2660.       Usage();
  2661.       }
  2662.     CreateCat(catalog);
  2663.     }
  2664.  
  2665.   if(newctfile)
  2666.     {
  2667.     CreateCTFile(newctfile);
  2668.     }
  2669.  
  2670.   MyExit(GlobalReturnCode);
  2671. }
  2672. //|
  2673. /// FUNC: wbmain
  2674.  
  2675. /*
  2676.     Dice's entry point for workbench programs
  2677. */
  2678. #if defined(__amigados)  &&  defined(_DCC)
  2679. void wbmain(struct WBStartup *wbmsg)
  2680. {
  2681.    fprintf(stderr, "FlexCat can't be run from Workbench!\n\n");
  2682.    fprintf(stderr, "Open a Shell session and type FlexCat\n");
  2683.    fprintf(stderr, "for syntax and more information\n");
  2684.  
  2685.    exit(5);
  2686. }
  2687. #endif
  2688. //|
  2689.  
  2690.